﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using OnTheWay.Models;
using OnTheWay.Interfaces;
using System.Collections.ObjectModel;
using OnTheWay.Exceptions;
using System.ComponentModel;

namespace OnTheWay.Functions
{
    [DesignTimeVisible(false)]
    public class FunctionCtrlList<T> : FunctionCtrlListBase where T : Model
    {
        protected IObjectBasicBehaviors<T, Guid> mDomain;

        public FunctionCtrlList()
        {
            OnInitializeSingleSearch(typeof(T));
        }

        public FunctionCtrlList(IObjectBasicBehaviors<T, Guid> domain)
            : this()
        {
            this.mDomain = domain;
        }

        public FunctionCtrlList(IObjectBasicBehaviors<T, Guid> domain, Type funmodel)
            : this(domain)
        {
            this.mFunmodel = funmodel;
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
            if (mDomain != null && WaitVisibility != Visibility.Visible)
            {
                OnCommandRefresh(null);
            }
        }

        #region 分页指示数据

        /// <summary>
        /// 统计数据总条数（用于计算PageCount页数，在异步线程中调用，子类可以重写这个方法计算）
        /// </summary>
        /// <returns></returns>
        protected override long GetItemCount()
        {
            if (mDomain != null)
            {
                return mDomain.GetRecordCount(mSqlWhere);
            }
            return 0;
        }

        #endregion

        #region 页面交互
        /// <summary>
        /// 在功能栈中添加FunctionCtrlModel进行数据添加
        /// </summary>
        /// <param name="fun"></param>
        protected void FunctionStackPutAdd(FunctionCtrlModel<T> fun)
        {
            fun.SetOnAdded(x => Items.Insert(0, x));
            fun.OperateMode = FunctionCtrlModel<T>.OperateModeEnum.Add;
            fun.Model = fun.OnInitializeModel(null);
            if (fun.Model == null)
            {
                ExceptionHandle.Handle(new Exception(), fun.GetType().FullName + " OnInitializeModel（添加时候）返回null ");
            }
            base.FunctionStackPut(fun);
        }
        /// <summary>
        /// 在功能栈中添加FunctionCtrlModel进行数据编辑
        /// </summary>
        /// <param name="fun">true 添加成功 false 添加失败（model不在Items中）</param>
        protected bool FunctionStackPutEdit(FunctionCtrlModel<T> fun, T model)
        {
            int index = Items.IndexOf(model);
            if (index >= 0)
            {
                fun.SetOnEdited(x => Items[index] = x);
                fun.OperateMode = FunctionCtrlModel<T>.OperateModeEnum.Modify;
                fun.Model = fun.OnInitializeModel(model.Clone<T>());
                base.FunctionStackPut(fun);
                return true;
            }
            return false;
        }

        #endregion

        #region 列表数据源

        private T mSelectedItem;
        private ObservableCollection<T> mSelectedItems = new ObservableCollection<T>();
        private ObservableCollection<T> mItems = new ObservableCollection<T>();

        /// <summary>
        //列表数据源
        /// </summary>
        public ObservableCollection<T> Items
        {
            get { return mItems; }
            set { if (mItems == value)return; mItems = value; this.PropertyNotifyChanged("Items"); }
        }
        /// <summary>
        /// 异步设置数据源
        /// </summary>
        public ObservableCollection<T> DispatchItems
        {
            set
            {
                this.Dispatcher.Invoke(new Action(() =>
                {
                    Items = value;
                }));
            }
        }

        /// <summary>
        /// 选择数据项
        /// </summary>
        public ObservableCollection<T> SelectedItems
        {
            get { return mSelectedItems; }
            set { if (mSelectedItems == value)return; mSelectedItems = value; this.PropertyNotifyChanged("SelectedItems"); }
        }

        /// <summary>
        /// 当前选择项
        /// </summary>
        public T SelectedItem
        {
            get { return mSelectedItem; }
            set { if (mSelectedItem != null && mSelectedItem.Equals(value))return; mSelectedItem = value; this.PropertyNotifyChanged("SelectedItem"); }
        }

        #endregion

        #region 实现命令功能
        /// <summary>
        /// 添加数据命令
        /// </summary>
        /// <param name="obj"></param>
        protected override void OnCommandAdd(object obj)
        {
            if (mFunmodel != null)
            {
                try
                {
                    FunctionCtrlModel<T> fun = mFunmodel.Assembly.CreateInstance(mFunmodel.FullName) as FunctionCtrlModel<T>;
                    if (fun != null)
                    {
                        FunctionStackPutAdd(fun);
                    }
                }
                catch (Exception ex)
                {
                    ExceptionHandle.Handle(ex, "FunctionCtrlList 列表页启动添加页面（OnCommandAdd->CreateInstance）出现异常");
                }
            }
            else if (mDomain != null && (obj is T))
            {
                this.PostTask(() =>
                {
                    T item = (T)obj;
                    DispatchWaitVisibility = Visibility.Visible;
                    DispatchWaitMessage = "正在添加数据....";
                    try
                    {
                        mDomain.Insert(item);
                        Dispatcher.Invoke(new Action(() =>
                        {
                            if (Items.IndexOf(item) < 0)
                            {
                                Items.Insert(0, item);
                            }
                            MessageStatus = Enums.MessageStatusEnum.Success;
                            Message = "添加数据成功完成";
                        }));
                    }
                    catch (System.Exception ex)
                    {
                        DispatchMessageStatus = Enums.MessageStatusEnum.Error;
                        DispatchMessage = "添加数据失败：" + ExceptionHandle.GetMessage(ex);
                    }

                    DispatchWaitVisibility = Visibility.Collapsed;
                });
            }
        }
        /// <summary>
        /// 修改数据命令
        /// </summary>
        /// <param name="obj"></param>
        protected override void OnCommandModify(object obj)
        {
            if (obj is T || SelectedItem is T)
            {
                T item = SelectedItem;
                if (obj is T)
                {
                    item = (T)obj;
                }
                if (mFunmodel != null)
                {
                    try
                    {
                        FunctionCtrlModel<T> fun = mFunmodel.Assembly.CreateInstance(mFunmodel.FullName) as FunctionCtrlModel<T>;
                        if (fun != null)
                        {
                            FunctionStackPutEdit(fun, item);
                        }
                    }
                    catch (Exception ex)
                    {
                        ExceptionHandle.Handle(ex, "FunctionCtrlList 列表页启动编辑页面（OnCommandModify->CreateInstance）出现异常");
                    }
                }
                else if (mDomain != null)
                {
                    this.PostTask(() =>
                    {
                        DispatchWaitVisibility = Visibility.Visible;
                        DispatchWaitMessage = "正在提交修改....";
                        try
                        {
                            mDomain.Update(item);
                            DispatchMessageStatus = Enums.MessageStatusEnum.Success;
                            DispatchMessage = "提交修改成功完成";
                        }
                        catch (System.Exception ex)
                        {
                            DispatchMessageStatus = Enums.MessageStatusEnum.Error;
                            DispatchMessage = "提交修改失败：" + ExceptionHandle.GetMessage(ex);
                        }

                        DispatchWaitVisibility = Visibility.Collapsed;
                    });
                }
            }
        }
        /// <summary>
        /// 删除数据命令
        /// </summary>
        /// <param name="obj"></param>
        protected override void OnCommandDelete(object obj)
        {
            base.OnCommandDelete(obj);
            if (mDomain != null && (obj is T || obj is ICollection<T> || SelectedItem is T))
            {
                IList<T> list = new List<T>();
                if (obj != null && obj is T)
                {
                    list.Add((T)obj);
                }
                else if (obj != null && obj is ICollection<T>)
                {
                    list = new List<T>((ICollection<T>)obj);
                }
                else if (mSelectedItems.Count > 0)
                {
                    list = new List<T>(mSelectedItems);
                }
                else if (SelectedItem is T)
                {
                    list.Add(SelectedItem);
                }
                if (list.Count == 0
                    || (list.Count == 1 && MessageBox.Show(this.ParentWindow, "确定要删除 【" + (list[0] as T).Name + "】 吗？", "提问", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
                    || (list.Count > 1 && MessageBox.Show(this.ParentWindow, "确定要删除 【" + list.Count + "】 个对象吗？", "提问", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel))
                {
                    return;
                }
                this.PostTask(() =>
                {
                    DispatchWaitVisibility = Visibility.Visible;
                    DispatchWaitMessage = "正在删除数据....";
                    try
                    {
                        mDomain.DeleteList(list);
                        Dispatcher.Invoke(new Action(() =>
                        {
                            foreach (var item in list)
                            {
                                Items.Remove(item);
                            }
                            MessageStatus = Enums.MessageStatusEnum.Success;
                            Message = "删除数据成功完成";
                        }));
                    }
                    catch (System.Exception ex)
                    {
                        DispatchMessageStatus = Enums.MessageStatusEnum.Error;
                        DispatchMessage = "删除数据失败：" + ExceptionHandle.GetMessage(ex);
                    }

                    DispatchWaitVisibility = Visibility.Collapsed;
                });
            }

        }
        /// <summary>
        /// 刷新数据命令
        /// </summary>
        /// <param name="obj"></param>
        private object lastsinglesearchitem = null;
        protected override void OnCommandRefresh(object obj)
        {
            base.OnCommandRefresh(obj);
            if (mDomain != null)
            {
                //开始新的搜索项 定位当前页到第一页
                if (lastsinglesearchitem != SingleSearchValue)
                {
                    PageIndex = 1;
                    lastsinglesearchitem = SingleSearchValue;
                }

                int pagesize = PageSize;
                int pageindex = PageIndex > 0 ? PageIndex - 1 : 0;
                Page page = PageSize > 0 ? new Page(pageindex, PageSize, mSqlOrder, mSqlDesc) : null;
                this.PostTask(() =>
                {
                    DispatchWaitVisibility = Visibility.Visible;
                    DispatchWaitMessage = "准备刷新数据....";
                    IList<T> list = new List<T>();
                    try
                    {
                        string where = BuildSingleSearchWhere(mSqlWhere);
                        if (page != null)
                        {
                            DispatchWaitMessage = "正在计算搜索....";
                            mTotalCount = mDomain.GetRecordCount(where);
                            int count = (int)(mTotalCount / pagesize) + ((mTotalCount % pagesize) > 0 ? 1 : 0);
                            mPageCount = count < 1 ? 1 : count;

                            DispatchWaitMessage = "正在刷新数据....";
                            list = mDomain.GetListByPage(where, page);
                        }
                        else
                        {
                            DispatchWaitMessage = "正在刷新数据....";
                            list = mDomain.GetListWhere(where, mSqlOrder, mSqlDesc ? "desc" : "asc");
                        }
                        
                        DispatchItems = new ObservableCollection<T>(list);
                        DispatchMessageStatus = Enums.MessageStatusEnum.Success;
                        DispatchMessage = "刷新数据成功完成";
                        DispatchPropertyNotifyChanged("ViewStart");
                        DispatchPropertyNotifyChanged("ViewEnd");
                        DispatchPropertyNotifyChanged("TotalCount");
                        DispatchPropertyNotifyChanged("PageCount");
                    }
                    catch (System.Exception ex)
                    {
                        OnCommandRefreshFail(ex);
                        DispatchMessageStatus = Enums.MessageStatusEnum.Error;
                        DispatchMessage = "数据加载失败：" + ExceptionHandle.GetMessage(ex);
                    }

                    DispatchWaitVisibility = Visibility.Collapsed;
                });
            }
        }

        protected virtual void OnCommandRefreshFail(Exception ex)
        {
            
        }

        #endregion

        #region 控件事件
        /// <summary>
        /// 选择改变事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void List_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
        {
            foreach (T item in e.RemovedItems)
            {
                SelectedItems.Remove(item);
            }
            foreach (T item in e.AddedItems)
            {
                SelectedItems.Add(item);
            }
        }
        #endregion
    }
    
    [DesignTimeVisible(false)]
    public class FunctionCtrlListBase : FunctionCtrlWait
    {
        protected bool mSqlDesc = true;
        protected string mSqlOrder = "";
        protected string mSqlWhere = "";
        protected Type mFunmodel;

        public FunctionCtrlListBase()
        {
            this.IsDurable = true;
        }

        #region 分页指示数据

        private ObservableCollection<int> mPageSizeItems = new ObservableCollection<int>() { 10, 15, 20, 30, 50, 100 };
        /// <summary>
        ///分页项数据
        /// </summary>
        public ObservableCollection<int> PageSizeItems
        {
            get { return mPageSizeItems; }
            set { if (mPageSizeItems == value)return; mPageSizeItems = value; this.PropertyNotifyChanged("PageSizeItems"); }
        }
        /// <summary>
        /// 起始数
        /// </summary>
        public int ViewStart { get { int index = PageIndex < 1 ? 1 : PageIndex; return (index - 1) * PageSize; } }
        /// <summary>
        /// 起始数
        /// </summary>
        public int ViewEnd { get { int count = ViewStart + PageSize; return (count < TotalCount) ? count : (int)TotalCount; } }
        /// <summary>
        /// 数据总量
        /// </summary>
        internal long mTotalCount = 0;
        public long TotalCount
        {
            get { return mTotalCount; }
            set { mTotalCount = value; PropertyNotifyChanged("TotalCount"); }
        }
        /// <summary>
        /// 分页总大小（内部计算得到,最小值1）
        /// </summary>
        internal int mPageCount = 1;
        public int PageCount
        {
            get { return mPageCount; }
            internal set { mPageCount = (value < 1 ? 1 : value); PropertyNotifyChanged("PageCount"); }
        }

        internal void CountingPage(int pagesize)
        {
            mTotalCount = this.GetItemCount();
            int count = (int)(mTotalCount / pagesize) + ((mTotalCount % pagesize) > 0 ? 1 : 0);
            mPageCount = count < 1 ? 1 : count;
            if (mPageIndex > mPageCount)
            {
                mPageIndex = 1;
                DispatchPropertyNotifyChanged("PageIndex");
            }
            DispatchPropertyNotifyChanged("PageCount");
            DispatchPropertyNotifyChanged("TotalCount");
        }

        protected void CountPage(int pagesize)
        {
            PostTask(() =>
            {
                CountingPage(pagesize);
            });
        }
        /// <summary>
        /// 统计数据总条数（用于计算PageCount页数，在异步线程中调用，子类可以重写这个方法计算）
        /// </summary>
        /// <returns></returns>
        protected virtual long GetItemCount()
        {
            return 0;
        }

        /// <summary>
        /// 分页单页大小（页面操作指定,等于0忽略分页功能，默认0）
        /// </summary>
        public int PageSize
        {
            get { return (int)GetValue(PageSizeProperty); }
            set
            {
                if (PageSize != value)
                {
                    SetValue(PageSizeProperty, value);
                }
            }
        }

        // Using a DependencyProperty as the backing store for PageSize.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty PageSizeProperty =
            DependencyProperty.Register("PageSize", typeof(int), typeof(FunctionCtrlListBase),
            new FrameworkPropertyMetadata(0, OnPageSizePropertyChanged));

        public static void OnPageSizePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FunctionCtrlListBase ctrl = d as FunctionCtrlListBase;
            bool refresh = 0 != (int)e.OldValue && ctrl.WaitVisibility != Visibility.Visible;
            ctrl.PostTask(() =>
            {
                ctrl.CountingPage((int)e.NewValue);
                if (refresh)
                {
                    ctrl.Dispatcher.Invoke(new Action(() =>
                    {
                        ctrl.OnCommandRefresh(null);
                    }));
                }
            });
        }
        /// <summary>
        /// 分页当前页（从1开始）
        /// </summary>
        internal int mPageIndex = 1;
        public int PageIndex
        {
            get { return mPageIndex; }
            set { mPageIndex = value; PropertyNotifyChanged("PageIndex"); }
        }

        #endregion

        #region 单项搜索

        public enum SearchTypeEnunm
        {
            STRING,INTEGER,ENUM,DATE
        }

        public class SingleSearch
        {
            public string Name { get; set; }
            public string Property { get; set; }
            public SearchTypeEnunm Type { get; set; }
            public Array Enums { get; set; }

            public SingleSearch(string property,string name)
            {
                this.Name = name;
                this.Property = property;
                this.Type = SearchTypeEnunm.STRING;
            }

        }

        private ObservableCollection<SingleSearch> _SingleSearchItems = new ObservableCollection<SingleSearch>();

        /// <summary>
        //列表数据源
        /// </summary>
        public ObservableCollection<SingleSearch> SingleSearchItems
        {
            get { return _SingleSearchItems; }
            set { if (_SingleSearchItems == value)return; _SingleSearchItems = value; this.PropertyNotifyChanged("SingleSearchItems"); }
        }

        public SingleSearch SingleSearchItem { get; set; }

        public object SingleSearchValue { get; set; }

        public string BuildSingleSearchWhere()
        {
            if (SingleSearchValue == null || SingleSearchItem == null)
            {
                return "";
            }
            switch (SingleSearchItem.Type)
            {
                case SearchTypeEnunm.STRING:
                    if (SingleSearchValue.Equals(""))
                    {
                        return "";
                    }
                    return String.Format(" where {0} like '%{1}%' ", SingleSearchItem.Property, SingleSearchValue);
                case SearchTypeEnunm.INTEGER:
                    if (SingleSearchValue is int)
                    {
                        return String.Format(" where {0} = {1} ", SingleSearchItem.Property, SingleSearchValue);
                    }
                    return "";
                case SearchTypeEnunm.ENUM:
                    try
                    {
                        return String.Format(" where {0} = {1} ", SingleSearchItem.Property, (int)SingleSearchValue);
                    }
                    catch (Exception)
                    {
                    }
                    return "";
                case SearchTypeEnunm.DATE:
                    if (SingleSearchValue is DateTime)
                    {

                    }
                    return "";
            }
            return "";
        }

        public string BuildSingleSearchWhere(string where)
        {
            string swhere = BuildSingleSearchWhere();
            if (swhere.Length > 0)
            {
                if (String.IsNullOrWhiteSpace(where))
                {
                    return swhere;
                }
                return swhere + AndWhere(where);
            }
            return where;
        }

        protected virtual void OnInitializeSingleSearch(Type type)
        {
            if (type.IsDefined(typeof(DataBaseTableAttribute), false))
            {
                foreach (var item in type.GetProperties())
                {
                    if (item.IsDefined(typeof(DataBaseMemberAttribute), false))
                    {
                        DataBaseMemberAttribute member = item.GetCustomAttributes(typeof(DataBaseMemberAttribute), false)[0] as DataBaseMemberAttribute;
                        if (!String.IsNullOrEmpty(member.Detail))
                        {
                            if (item.PropertyType.Equals(typeof(string)))
                            {
                                SingleSearchItems.Add(new SingleSearch(item.Name, member.Detail));
                            }
                            else if (member.EnumType != null && member.EnumType.IsEnum)
                            {
                                SingleSearch entity = new SingleSearch(item.Name, member.Detail);
                                entity.Type = SearchTypeEnunm.ENUM;
                                entity.Enums = Enum.GetValues(member.EnumType);
                                SingleSearchItems.Add(entity);
                            }
                            else if (item.PropertyType.IsEnum)
                            {
                                SingleSearch entity = new SingleSearch(item.Name, member.Detail);
                                entity.Type = SearchTypeEnunm.ENUM;
                                entity.Enums = Enum.GetValues(item.PropertyType);
                                SingleSearchItems.Add(entity);
                            }
                            else if (item.PropertyType.Equals(typeof(int)) || item.PropertyType.Equals(typeof(long)))
                            {
                                SingleSearchItems.Add(new SingleSearch(item.Name, member.Detail) { Type = SearchTypeEnunm.INTEGER });
                            }
                        }
                    }
                }
            }
        }

        #endregion

        #region Sql辅助查询

        public static String Where(String where)
        {
            if (where != null)
            {
                String lower = where.ToLower();
                String Trim = lower.Trim();
                if (!Trim.Equals(""))
                {
                    if (Trim.StartsWith("where"))
                    {
                        return where;
                    }
                    return " where " + where;
                }
                return "";
            }
            else
            {
                return "";
            }
        }

        public static String AndWhere(String where)
        {
            // TODO Auto-generated method stub
            if (where != null)
            {
                String lower = where.ToLower();
                String Trim = lower.Trim();
                if (!Trim.Equals(""))
                {
                    if (Trim.StartsWith("where"))
                    {
                        where = where.Substring(lower.IndexOf('w') + 5);
                    }
                    return " and " + where;
                }
                return "";
            }
            else
            {
                return "";
            }
        }

        public static String OrWhere(String where)
        {
            // TODO Auto-generated method stub
            if (where != null)
            {
                String lower = where.ToLower();
                String Trim = lower.Trim();
                if (!Trim.Equals(""))
                {
                    if (Trim.StartsWith("where"))
                    {
                        where = where.Substring(lower.IndexOf('w') + 5);
                    }
                    return " or " + where;
                }
                return "";
            }
            else
            {
                return "";
            }
        }

        #endregion

    }
}
